package com.smartleanx.module.hrm.service.salary;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.smartleanx.framework.datapermission.core.annotation.DataPermission;
import com.smartleanx.framework.mybatis.core.dataobject.BaseDO;
import com.smartleanx.framework.security.core.util.SecurityFrameworkUtils;
import com.smartleanx.framework.tenant.core.context.TenantContextHolder;
import com.smartleanx.framework.tenant.core.db.TenantBaseDO;
import com.smartleanx.module.hrm.controller.admin.dingDing.bo.DingAttendanceConfirmationBo;
import com.smartleanx.module.hrm.controller.admin.employee.vo.EmployeeImportRespVO;
import com.smartleanx.module.hrm.dal.dataobject.employee.EmployeeDO;
import com.smartleanx.module.hrm.dal.dataobject.employee.EmployeeExcelDO;
import com.smartleanx.module.hrm.dal.dataobject.salary.*;
import com.smartleanx.module.hrm.dal.dataobject.salary.vo.HrmSalaryTableConfigVo;
import com.smartleanx.module.hrm.dal.mysql.employee.EmployeeMapper;
import com.smartleanx.module.hrm.dal.mysql.salary.*;
import com.smartleanx.module.hrm.framework.excel.CustomCellWriteWidthConfig;
import com.smartleanx.module.hrm.framework.excel.MonthSheetWriteHandler;
import com.smartleanx.module.hrm.service.dingDing.DingUserService;
import com.smartleanx.module.hrm.service.examine.util.DateUtil;
import com.smartleanx.module.hrm.service.examine.util.exception.ResultException;
import com.smartleanx.module.system.api.dept.DeptApi;
import com.smartleanx.module.system.api.dept.dto.DeptRespDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.smartleanx.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.smartleanx.module.hrm.enums.ErrorCodeConstants.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mybatis-plus
 * @since 2025-01-07
 */
@Service
public class HrmSalaryTemplateServiceImpl implements HrmSalaryTemplateService {

    @Autowired
    private HrmSalaryTemplateMapper hrmSalaryTemplateMapper;
    @Autowired
    private HrmSalaryTemplateInfoMapper hrmSalaryTemplateInfoMapper;
    @Autowired
    private HrmSalaryTableConfigTenantMapper salaryTableConfigTenantMapper;
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private HrmSalaryTableConfigTenantMapper hrmSalaryTableConfigTenantMapper;
    @Autowired
    private SystemColumnMapper systemColumnMapper;
    @Autowired
    private SystemColumnTenantMapper systemColumnTenantMapper;
    @Autowired
    private SystemColumnValueMapper systemColumnValueMapper;
    @Autowired
    private SystemColumnValueService systemColumnValueService;
    @Autowired
    private DeptApi deptApi;
    @Autowired
    private DingUserService dingUserService;

    private final String titleRow = "温馨提示：'*'为必填项,为确保数据准确处理，请正确填写单元格数据,避免导入失败。";

    @Override
    public List<HrmSalaryTableConfigVo> firstSelectTableList() {
        List<HrmSalaryTableConfigVo> salaryTableConfigVoList = new ArrayList<>();
        List<HrmSalaryTableConfigTenant> hrmSalaryTableConfigs = hrmSalaryTableConfigTenantMapper.selectList(new LambdaQueryWrapper<HrmSalaryTableConfigTenant>() {{
            eq(HrmSalaryTableConfigTenant::getType, 1);
            ne(HrmSalaryTableConfigTenant::getPid, 0);
            eq(HrmSalaryTableConfigTenant::getIsDisplayed, 1);
        }});
        if (!ObjectUtils.isEmpty(hrmSalaryTableConfigs)) {
            hrmSalaryTableConfigs.forEach(hrmSalaryTableConfig -> {

                HrmSalaryTableConfigVo hrmSalaryTableConfigVo = new HrmSalaryTableConfigVo();
                BeanUtils.copyProperties(hrmSalaryTableConfig, hrmSalaryTableConfigVo);
//                hrmSalaryTableConfigVo.setIsTaxation("是否计税");
                hrmSalaryTableConfigVo.setIsAddSubtract("加/减项");
                List<HrmSalaryTableConfigTenant> hrmSalaryTableConfigSons = hrmSalaryTableConfigTenantMapper.selectList(new LambdaQueryWrapper<HrmSalaryTableConfigTenant>() {{
                    eq(HrmSalaryTableConfigTenant::getPid, hrmSalaryTableConfig.getId());
                    eq(HrmSalaryTableConfigTenant::getIsDisplayed, 1);
                }});

                if (!ObjectUtils.isEmpty(hrmSalaryTableConfigSons)) {
                    List<HrmSalaryTableConfigVo> hrmSalaryTableConfigVoSons = new ArrayList<>();
                    hrmSalaryTableConfigSons.forEach(hrmSalaryTableConfigSon -> {
                        HrmSalaryTableConfigVo hrmSalaryTableConfigVo1 = new HrmSalaryTableConfigVo();
                        BeanUtils.copyProperties(hrmSalaryTableConfigSon, hrmSalaryTableConfigVo1);
//                        hrmSalaryTableConfigVo1.setIsTaxation(hrmSalaryTableConfig.getIsTaxation() + "");
                        hrmSalaryTableConfigVo1.setIsAddSubtract(hrmSalaryTableConfig.getIsAddSubtract() + "");
                        hrmSalaryTableConfigVoSons.add(hrmSalaryTableConfigVo1);
                    });
                    hrmSalaryTableConfigVo.setChildren(hrmSalaryTableConfigVoSons);
                } else {
                    hrmSalaryTableConfigVo.setChildren(new ArrayList<>());
                }
                salaryTableConfigVoList.add(hrmSalaryTableConfigVo);
            });
        }
        return salaryTableConfigVoList;
    }

    @Override
    public List<HrmSalaryTemplate> findSalaryTemplateAll() {
        List<HrmSalaryTemplate> hrmSalaryTemplates = hrmSalaryTemplateMapper.selectList(null);
        hrmSalaryTemplates.forEach(hrmSalaryTemplate -> {
            hrmSalaryTemplate.setTableNames(hrmSalaryTemplateInfoMapper.selectList(new LambdaQueryWrapper<HrmSalaryTemplateInfo>(
            ) {{
                eq(HrmSalaryTemplateInfo::getTemplateId, hrmSalaryTemplate.getId());
            }}).stream().map(a -> salaryTableConfigTenantMapper.selectById(a.getTableId()).getName()).collect(Collectors.toList()));
        });


        return hrmSalaryTemplates;
    }

    @Override
    public void insertSalaryTemplate(HrmSalaryTemplate hrmSalaryTemplate) {
        Integer createBy = -1;
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        EmployeeDO employeeDO = employeeMapper.selectOne(new LambdaQueryWrapper<EmployeeDO>() {{
            eq(EmployeeDO::getUserId, loginUserId);
        }});
        if (!ObjectUtils.isEmpty(employeeDO)) {
            createBy = employeeDO.getId().intValue();
        }
        if (ObjectUtils.isEmpty(hrmSalaryTemplate.getTableIds())) {
            throw new ResultException("新增模版，默认设置薪资项不能为空");
        }
        hrmSalaryTemplate.setCreateTime(DateUtil.currentDateFormat());
        hrmSalaryTemplate.setCreateBy(createBy);
        hrmSalaryTemplateMapper.insert(hrmSalaryTemplate);
        hrmSalaryTemplate.getTableIds().forEach(tableId -> {
            HrmSalaryTemplateInfo salaryTemplateInfo = new HrmSalaryTemplateInfo();
            salaryTemplateInfo.setTemplateId(hrmSalaryTemplate.getId());
            salaryTemplateInfo.setTableId(tableId);
            salaryTemplateInfo.setCreateTime(DateUtil.currentDateFormat());
            hrmSalaryTemplateInfoMapper.insert(salaryTemplateInfo);
        });
    }

    @Override
    public void updateSalaryTemplate(HrmSalaryTemplate hrmSalaryTemplate) {
        Integer createBy = -1;
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        EmployeeDO employeeDO = employeeMapper.selectOne(new LambdaQueryWrapper<EmployeeDO>() {{
            eq(EmployeeDO::getUserId, loginUserId);
        }});
        if (!ObjectUtils.isEmpty(employeeDO)) {
            createBy = employeeDO.getId().intValue();
        }
        if (ObjectUtils.isEmpty(hrmSalaryTemplate.getTableIds())) {
            throw new ResultException("新增模版，默认设置薪资项不能为空");
        }
        if (ObjectUtils.isEmpty(hrmSalaryTemplate.getId())) {
            throw new ResultException("请刷新页面重试");
        }
        hrmSalaryTemplate.setCreateTime(DateUtil.currentDateFormat());
        hrmSalaryTemplate.setCreateBy(createBy);
        hrmSalaryTemplateMapper.updateById(hrmSalaryTemplate);

        hrmSalaryTemplateInfoMapper.delete(new LambdaQueryWrapper<HrmSalaryTemplateInfo>() {{
            eq(HrmSalaryTemplateInfo::getTemplateId, hrmSalaryTemplate.getId());
        }});
        hrmSalaryTemplate.getTableIds().forEach(tableId -> {
            HrmSalaryTemplateInfo salaryTemplateInfo = new HrmSalaryTemplateInfo();
            salaryTemplateInfo.setTemplateId(hrmSalaryTemplate.getId());
            salaryTemplateInfo.setTableId(tableId);
            salaryTemplateInfo.setCreateTime(DateUtil.currentDateFormat());
            hrmSalaryTemplateInfoMapper.insert(salaryTemplateInfo);
        });
    }

    @Override
    public HrmSalaryTemplate selectSalaryTemplateById(Long id) {
        List<JSONObject> resultList = new ArrayList<>();
        List<JSONObject> syResultList = new ArrayList<>();
        HrmSalaryTemplate hrmSalaryTemplate = hrmSalaryTemplateMapper.selectById(id);
        hrmSalaryTemplate.setTableIds(hrmSalaryTemplateInfoMapper.selectList(new LambdaQueryWrapper<HrmSalaryTemplateInfo>(
        ) {{
            eq(HrmSalaryTemplateInfo::getTemplateId, hrmSalaryTemplate.getId());
        }}).stream().map(HrmSalaryTemplateInfo::getTableId).collect(Collectors.toList()));
        hrmSalaryTemplate.setSyTableIds(hrmSalaryTemplateInfoMapper.selectList(new LambdaQueryWrapper<HrmSalaryTemplateInfo>(
        ) {{
            eq(HrmSalaryTemplateInfo::getTemplateId, hrmSalaryTemplate.getId());
        }}).stream().map(HrmSalaryTemplateInfo::getTableId).collect(Collectors.toList()));
        List<HrmSalaryTableConfigTenant> hrmSalaryTableConfigTenants = hrmSalaryTableConfigTenantMapper.selectBatchIds(hrmSalaryTemplate.getTableIds());
        hrmSalaryTableConfigTenants.forEach(h -> {
            JSONObject result = new JSONObject();
            result.put("id", h.getId());
            result.put("value", h.getName());
            resultList.add(result);
            syResultList.add(result);
        });
        hrmSalaryTemplate.setTables(resultList);
        hrmSalaryTemplate.setSyTables(syResultList);
        return hrmSalaryTemplate;
    }


    @Override
    public void deleteSalaryTemplateById(Long id) {
        hrmSalaryTemplateMapper.deleteById(id);
        hrmSalaryTemplateInfoMapper.delete(new LambdaQueryWrapper<HrmSalaryTemplateInfo>() {{
            eq(HrmSalaryTemplateInfo::getTemplateId, id);
        }});
    }

    @Override
    @DataPermission(enable = true) //是否开启权限
    public void downloadTemp(HttpServletResponse response) {
        Long tenantId = TenantContextHolder.getTenantId();
        //1. 获取表头
        List<SystemColumnTenant> columnList = getColumnTenantList(tenantId);

        //2. 设置表头
        List<List<String>> headList = new ArrayList<>();
        //2.1 通过反射获取类中注解值  需要增加固定字段  只需在类中添加属性
        Field[] declaredFields = EmployeeExcelDO.class.getDeclaredFields();
        for (Field field : declaredFields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            String[] value = annotation.value();
            for (String s : value) {
                addHeadItem(headList,s);
            }
        }
        //2.2 自定义字段
        for (SystemColumnTenant column : columnList) {
            String name = column.getName();
            if("should_attendance_days".equals(column.getAlias())){
                name = "*"+name;
            }
            addHeadItem(headList,name);
        }

        //3. 获取员工
        List<EmployeeDO> employeeDOS = employeeMapper.selectList(new LambdaQueryWrapper<EmployeeDO>()
        .isNull(EmployeeDO::getApplySeparationTime)
                .eq(BaseDO::getDeleted,0)
                .eq(TenantBaseDO::getTenantId,tenantId));

        //4. 设置响应头
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = null;
        try {
            fileName = URLEncoder.encode("钉钉导入模板.xlsx", "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);

        //5. 写出
        try{
            List<Long> deptIds = employeeDOS.parallelStream().map(EmployeeDO::getDeptId).collect(Collectors.toList());
            List<DeptRespDTO> deptDoList = deptApi.getAllDeptListBatchIds(deptIds).getData();
            Map<Long, DeptRespDTO> deptMap = deptDoList.parallelStream().collect(Collectors.toMap(DeptRespDTO::getId,Function.identity()));
            List<EmployeeExcelDO> employeeExcelDOList = employeeDOS.stream().map(p -> {
                EmployeeExcelDO employeeExcelDO = new EmployeeExcelDO();
                employeeExcelDO.setName(p.getName());
                employeeExcelDO.setEmployeeNo(p.getEmployeeNo());
                employeeExcelDO.setSex("1".equals(p.getSex()+"") ? "男" : "女");
                employeeExcelDO.setDeptName(null == deptMap.get(p.getDeptId())?"暂无部门":deptMap.get(p.getDeptId()).getName());
                return employeeExcelDO;
            }).collect(Collectors.toList());
            // 构建模板数据
            EasyExcel.write(response.getOutputStream())
                    .relativeHeadRowIndex(1)
                    .registerWriteHandler(new CustomCellWriteWidthConfig()) // 基于 column 长度，自动适配。最大 255 宽度
                    .registerWriteHandler(new MonthSheetWriteHandler(titleRow, headList.size()))
                    .head(headList)
                    .sheet("钉钉导入模板")
                    .doWrite(employeeExcelDOList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void addHeadItem(List<List<String>> headList,String value){
        List<String> item = new ArrayList<>();
        item.add(value);
        headList.add(item);
    }

    @Override
    public EmployeeImportRespVO importTemp(MultipartFile file, DingAttendanceConfirmationBo confirmationBo){
        String date = confirmationBo.getDate();

        Long tenantId = TenantContextHolder.getTenantId();
        if(null == date){
            throw  new ResultException("请选择日期");
        }
        //1. 获取数据库表头
        List<SystemColumnTenant> columnList = getColumnTenantList(tenantId);
        Map<String, SystemColumnTenant> columnMap = columnList.stream().collect(Collectors.toMap(SystemColumnTenant::getName, Function.identity()));

        //2. 文件是否为空
        if (file == null) {
            throw exception(DATA_IS_EMPTY);
        }
        //3. 创建容器保存表头和数据
        List<Map<String, Object>> dataList = new ArrayList<>();
        try {
            EasyExcel.read(file.getInputStream(), new AnalysisEventListener<Map<Integer, String>>() {
                private Map<Integer, String> headerMap;

                @Override
                public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                    this.headerMap = headMap;
                }

                @Override
                public void invoke(Map<Integer, String> data, AnalysisContext context) {
                    // 将行数据转换为Map格式
                    Map<String, Object> rowData = new LinkedHashMap<>();
                    headerMap.forEach((key,value) ->{
                        rowData.put(value, data.get(key));
                    });
                    dataList.add(rowData);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                }

            }).headRowNumber(2).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }

        EmployeeImportRespVO respVO = EmployeeImportRespVO.builder().updateNames(new ArrayList<>()).createNames(new ArrayList<>()).failureNames(new HashMap<>()).build();

        //4. 判断数据是否为空
        if(!dataList.isEmpty()){
            //4.1 循环数据组
            List<EmployeeDO> employeeDOS = employeeMapper.selectList(new LambdaQueryWrapper<EmployeeDO>()
                    .eq(TenantBaseDO::getTenantId,tenantId)
                    .eq(BaseDO::getDeleted,0));
            Map<String, EmployeeDO> employeeMap = employeeDOS.parallelStream().collect(Collectors.toMap(EmployeeDO::getEmployeeNo,Function.identity()));
            List<List<Object>> errorData = new ArrayList<>();
            List<SystemColumnValue> valueList = new ArrayList<>();
            Map<Integer,Map<String, Object>> errorMap = new HashMap<>();
            int rowNum = 0;
            for (Map<String, Object> map : dataList) {
                rowNum++;

                //4.2 获取员工信息
                EmployeeDO employee = employeeMap.get(map.get("工号").toString());
                //4.3 判断员工是否符合要求    1.在职 是否在时间内入职   2.离职 是否在时间外离职  确保有考勤记录
                if(null == employee){
                    respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"不在时间范围内");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("该员工不存在");
                    errorData.add(errorList);
                    continue;
                }else if(null == employee.getApplySeparationTime()){
                    //4.3.1 在职人员  通过入职 时间  判断是否在选择日期之前
                    String entryTime = cn.hutool.core.date.DateUtil.format(employee.getEntryTime(), "yyyy-MM");
                    // 日期转换  保留年月  保证数据匹配
                    if(cn.hutool.core.date.DateUtil.compare(cn.hutool.core.date.DateUtil.parse(entryTime, "yyyy-MM"), cn.hutool.core.date.DateUtil.parse(date, "yyyy-MM")) > 0){
                        respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "不在时间范围内");
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("员工在"+date+"未入职");
                        errorData.add(errorList);
                        continue;
                    }
                }else{
                    //4.3.2 离职人员  通过里 时间  判断是否在选择日期之后
                    String separationTime = cn.hutool.core.date.DateUtil.format(employee.getApplySeparationTime(), "yyyy-MM");
                    // 日期转换  保留年月  保证数据匹配
                    if(cn.hutool.core.date.DateUtil.compare(cn.hutool.core.date.DateUtil.parse(separationTime, "yyyy-MM"), cn.hutool.core.date.DateUtil.parse(date, "yyyy-MM")) > 0){
                        respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"不在时间范围内");
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("员工在"+date+"前已离职");
                        errorData.add(errorList);
                        continue;
                    }
                }

                //检测必填项
                boolean flag = true;
                for (String key : map.keySet()) {
                    if(flag && key.contains("(*)")){
                        flag = map.get(key) != null;
                        if(!flag){
                            respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"必填项未填写");
                            ArrayList<Object> errorList = new ArrayList<>(map.values());
                            errorList.add(key+"未填写");
                            errorData.add(errorList);
                        }
                    }
                }
                if(!flag){
                    continue;
                }

                //4.4 map格式为 {休息天数=1, 婚假=1}
                map.forEach((key,value) ->{
                    if(key.contains("*")){
                        key = key.replace("*","");
                    }
                    SystemColumnTenant systemColumn = columnMap.get(key);
                    if(null != systemColumn){
                        SystemColumnValue systemColumnValue = new SystemColumnValue();
                        systemColumnValue.setColumnId(systemColumn.getId());
                        systemColumnValue.setColumnValue(null==value?null:value.toString());
                        systemColumnValue.setTenantId(tenantId.intValue());
                        systemColumnValue.setDingUserId(employee.getId().intValue());
                        systemColumnValue.setDate(date);
                        systemColumnValue.setEmployeeNo(employee.getEmployeeNo());
                        systemColumnValue.setEmployeeName(employee.getName());
                        valueList.add(systemColumnValue);
                    }

                });
                errorMap.put(employee.getId().intValue(),map);

            }
            List<Long> empids = valueList.stream().map(SystemColumnValue::getDingUserId).distinct().map(Long::new).collect(Collectors.toList());
            try{
                systemColumnValueService.saveBatch(valueList);
            }catch (Exception e){
                // 异常数据处理
                QueryWrapper<SystemColumnValue> queryWrapper = new QueryWrapper<>();
                queryWrapper.select("DISTINCT ding_user_id").lambda()
                        .eq(SystemColumnValue::getDate,date)
                        .in(SystemColumnValue::getDingUserId,valueList.stream().map(SystemColumnValue::getDingUserId).collect(Collectors.toList()))
                        .eq(SystemColumnValue::getTenantId,tenantId);
                List<SystemColumnValue> list = systemColumnValueService.list(queryWrapper);
                //数据库存在数据进行遍历
                for (SystemColumnValue systemColumnValue : list) {
                    // 导入数据列表 匹配数据库已有数据
                    empids.remove(systemColumnValue.getDingUserId().longValue());
                    respVO.getFailureNames().put(systemColumnValue.getDingUserId()+"", "["+systemColumnValue.getDingUserId()+"]"+"数据同时存在同一个人、同一个时间、同一条扣款");
                    Map<String, Object> map = errorMap.get(systemColumnValue.getDingUserId());
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("该员工已存在"+date+"的考勤记录");
                    errorData.add(errorList);
                }

            }
            respVO.setSuccessNum((dataList.size() - errorData.size())+"");

            //5. 错误数据
            if(CollUtil.isNotEmpty(errorData)){
                List<List<String>> finalHeader = new ArrayList<>();

                dataList.get(0).forEach((key,value) ->{
                    List<String> temp = new ArrayList<>();
                    temp.add(key);
                    finalHeader.add(temp);
                });
                List<String> eh = new ArrayList<>();
                eh.add("错误原因");
                finalHeader.add(eh);

                File excel = null;
                try {
                    excel = File.createTempFile("Error", ".xls");
                    excel.deleteOnExit();
                    EasyExcel.write(new FileOutputStream(excel)).sheet("。。。。。").head(finalHeader)
                            .doWrite(errorData);
                    respVO.setFileName(excel.getName());
                    respVO.setFilePath(excel.getAbsolutePath());
                } catch (Exception e) {
                    System.err.println(e.getLocalizedMessage());
                }
            }


            //6. 生成记录   总数据 减 异常数据  大于0  等于成功条数
            if(dataList.size() - errorData.size() >= 0){
                confirmationBo.setEmpIds(empids);
                dingUserService.generateColumnSystem(confirmationBo);
            }
        }
        return respVO;
    }

    @Override
    public EmployeeImportRespVO verifyImportData(MultipartFile file, DingAttendanceConfirmationBo confirmationBo) {
        String date = confirmationBo.getDate();

        Long tenantId = TenantContextHolder.getTenantId();
        if(null == date){
            throw  new ResultException("请选择日期");
        }

        //1. 获取数据库表头
        List<SystemColumnTenant> columnList = getColumnTenantList(tenantId);
        Map<String, SystemColumnTenant> columnMap = columnList.stream().collect(Collectors.toMap(SystemColumnTenant::getName, Function.identity()));

        //2. 文件是否为空
        if (file == null) {
            throw exception(DATA_IS_EMPTY);
        }
        //3. 创建容器保存表头和数据
        List<Map<String, Object>> dataList = new ArrayList<>();
        try {
            EasyExcel.read(file.getInputStream(), new AnalysisEventListener<Map<Integer, String>>() {
                private Map<Integer, String> headerMap;

                @Override
                public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                    this.headerMap = headMap;
                }

                @Override
                public void invoke(Map<Integer, String> data, AnalysisContext context) {
                    // 将行数据转换为Map格式
                    Map<String, Object> rowData = new LinkedHashMap<>();
                    headerMap.forEach((key,value) ->{
                        rowData.put(value, data.get(key));
                    });
                    dataList.add(rowData);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                }

            }).headRowNumber(2).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }

        EmployeeImportRespVO respVO = EmployeeImportRespVO.builder().updateNames(new ArrayList<>()).createNames(new ArrayList<>()).failureNames(new HashMap<>()).build();

        //4. 判断数据是否为空
        if(!dataList.isEmpty()){
            //4.1 循环数据组
            List<EmployeeDO> employeeDOS = employeeMapper.selectList(new LambdaQueryWrapper<EmployeeDO>()
                    .eq(TenantBaseDO::getTenantId,tenantId)
                    .eq(BaseDO::getDeleted,0));
            Map<String, EmployeeDO> employeeMap = employeeDOS.parallelStream().collect(Collectors.toMap(EmployeeDO::getEmployeeNo,Function.identity()));
            List<List<Object>> errorData = new ArrayList<>();
            List<List<Object>> writeData = new ArrayList<>();
            List<Long> empids = new ArrayList<>();
            Map<Integer,Map<String, Object>> errorMap = new HashMap<>();
            int rowNum = 0;

            for (Map<String, Object> map : dataList) {
                rowNum++;
                 if(!map.containsKey("工号")){
                     throw new ResultException("请按照原模版格式上传");
                 }

                //4.2 获取员工信息
                if(map.get("工号") == null){
                    respVO.getFailureNames().put("第" + rowNum + "行", "工号不能为空");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("工号不能为空");
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }

                if(map.get("员工姓名") == null){
                    respVO.getFailureNames().put("第" + rowNum + "行", "员工姓名不能为空");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("员工姓名不能为空");
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }

                if(map.get("性别") == null){
                    respVO.getFailureNames().put("第" + rowNum + "行", "性别不能为空");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("性别不能为空");
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }

                if(map.get("部门") == null){
                    respVO.getFailureNames().put("第" + rowNum + "行", "部门不能为空");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("部门不能为空");
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }
                EmployeeDO employee = employeeMap.get(map.get("工号").toString());
                //4.3 判断员工是否符合要求    1.在职 是否在时间内入职   2.离职 是否在时间外离职  确保有考勤记录
                if(null == employee){
                    respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"不在时间范围内");
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    errorList.add("该员工不存在");
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }else if(null == employee.getApplySeparationTime()){
                    //4.3.1 在职人员  通过入职 时间  判断是否在选择日期之前
                    String entryTime = cn.hutool.core.date.DateUtil.format(employee.getEntryTime(), "yyyy-MM");
                    // 日期转换  保留年月  保证数据匹配
                    if(cn.hutool.core.date.DateUtil.compare(cn.hutool.core.date.DateUtil.parse(entryTime, "yyyy-MM"), cn.hutool.core.date.DateUtil.parse(date, "yyyy-MM")) < 0){
                        respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "不在时间范围内");
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("员工在"+date+"未入职");
                        errorData.add(errorList);
                        writeData.add(errorList);
                        continue;
                    }
                }else{
                    //4.3.2 离职人员  通过里 时间  判断是否在选择日期之后
                    String separationTime = cn.hutool.core.date.DateUtil.format(employee.getApplySeparationTime(), "yyyy-MM");
                    // 日期转换  保留年月  保证数据匹配
                    if(cn.hutool.core.date.DateUtil.compare(cn.hutool.core.date.DateUtil.parse(separationTime, "yyyy-MM"), cn.hutool.core.date.DateUtil.parse(date, "yyyy-MM")) > 0){
                        respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"不在时间范围内");
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("员工在"+date+"前已离职");
                        errorData.add(errorList);
                        writeData.add(errorList);
                        continue;
                    }
                }

                //检测 1/必填项 2/数据格式
                boolean flag = true;
                //必填
                StringBuilder requiredErrorKey = new StringBuilder();
                //数据类型
                StringBuilder typeErrorKey = new StringBuilder();
                for (String key : map.keySet()) {
                    //检查带星号  必填项
                    if(key.contains("*")){
                        //字段拼接  返回错误数据
                        if(map.get(key) == null){
                            //只进一次   不满足条件
                            if(flag){
                                respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"必填项未填写");
                            }
                            flag = false;
                            if(!requiredErrorKey.toString().isEmpty()){
                                requiredErrorKey.append("、");
                            }
                            requiredErrorKey.append(key);
                        }
                    }
                    SystemColumnTenant systemColumn = columnMap.get(key);
                    // 1/数字类型
                    if(null != systemColumn && null != systemColumn.getDataType() &&
                          systemColumn.getDataType() == 1 && map.get(key) != null && !isNumeric(map.get(key)+"")){
                        if(flag){
                            respVO.getFailureNames().put("第" + rowNum + "行" + map.get("员工姓名"), "["+map.get("工号")+"]"+"数据填写错误");
                        }
                        if(!typeErrorKey.toString().isEmpty()){
                            typeErrorKey.append("、");
                        }
                        typeErrorKey.append(key);
                        flag = false;
                    }
                }
                if(!flag){
                    ArrayList<Object> errorList = new ArrayList<>(map.values());
                    requiredErrorKey.append("未填写");

                    if(!typeErrorKey.toString().isEmpty()){
                        requiredErrorKey.append(",").append(typeErrorKey.toString()).append("请填写数字");
                    }
                    errorList.add(requiredErrorKey.toString());
                    errorData.add(errorList);
                    writeData.add(errorList);
                    continue;
                }

                empids.add(employee.getId());
                errorMap.put(employee.getId().intValue(),map);
            }

            // 异常数据处理
            int successNum = 0;
            if(CollUtil.isNotEmpty(empids)){
                QueryWrapper<SystemColumnValue> queryWrapper = new QueryWrapper<>();
                queryWrapper.select("DISTINCT ding_user_id").lambda()
                        .eq(SystemColumnValue::getDate,date)
                        .in(SystemColumnValue::getDingUserId,empids)
                        .eq(SystemColumnValue::getTenantId,tenantId);
                List<SystemColumnValue> list = systemColumnValueService.list(queryWrapper);
                Map<Integer, SystemColumnValue> columnValueMap = list.stream().collect(Collectors.toMap(SystemColumnValue::getDingUserId, Function.identity()));
                //数据库存在数据进行遍历
                for (Long empid : empids) {
                    SystemColumnValue systemColumnValue = columnValueMap.get(empid.intValue());
                    if(null != systemColumnValue){
                        respVO.getFailureNames().put(systemColumnValue.getDingUserId()+"", "["+systemColumnValue.getDingUserId()+"]"+"数据同时存在同一个人、同一个时间、同一条扣款");
                        Map<String, Object> map = errorMap.get(systemColumnValue.getDingUserId());
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("该员工已存在"+date+"的考勤记录");
                        errorData.add(errorList);
                        writeData.add(errorList);
                    }else{
                        successNum++;
                        Map<String, Object> map = errorMap.get(empid.intValue());
                        ArrayList<Object> errorList = new ArrayList<>(map.values());
                        errorList.add("正常");
                        writeData.add(errorList);
                    }
                }
            }

            respVO.setSuccessNum(successNum+"");

            //5. 错误数据
            if(CollUtil.isNotEmpty(errorData)){
                List<List<String>> finalHeader = new ArrayList<>();

                dataList.get(0).forEach((key,value) ->{
                    List<String> temp = new ArrayList<>();
                    temp.add(key);
                    finalHeader.add(temp);
                });
                List<String> eh = new ArrayList<>();
                eh.add("错误原因");
                finalHeader.add(eh);

                File excel = null;
                try {
                    excel = File.createTempFile("Error", ".xls");
                    excel.deleteOnExit();

                    EasyExcel.write(new FileOutputStream(excel)).sheet("。。。。。")
                            .relativeHeadRowIndex(1).registerWriteHandler(new MonthSheetWriteHandler(titleRow, finalHeader.size()))
                            .head(finalHeader)
                            .doWrite(writeData);
                    respVO.setFileName(excel.getName());
                    respVO.setFilePath(excel.getAbsolutePath());
                } catch (Exception e) {
                    System.err.println(e.getLocalizedMessage());
                }
            }

        }

        try {
            respVO.setFile(file.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return respVO;
    }

    public Boolean isNumeric(String str){
        return str.matches("-?\\d+(\\.\\d+)?");
    }

    @Override
    public List<JSONObject> getColumn() {
        List<SystemColumnTenant> columnTenantList = getColumnTenantList(TenantContextHolder.getTenantId());
        List<JSONObject> resultList = new ArrayList<>();
        columnTenantList.forEach(column -> {
            JSONObject result = new JSONObject();
            result.put("id", column.getId());
            result.put("value", column.getName());
            result.put("type", column.getConfigType());
            resultList.add(result);
        });
        return resultList;
    }

    //获取考勤字段
    public  List<SystemColumnTenant> getColumnTenantList(Long tenantId){
        return systemColumnTenantMapper.selectList(new LambdaQueryWrapper<SystemColumnTenant>()
                .eq(SystemColumnTenant::getTenantId,tenantId)
                .eq(SystemColumnTenant::getColumnType,"2")
                .eq(SystemColumnTenant::getIsDel,"0")
                .eq(SystemColumnTenant::getStatus,1)
        );
    }

    public static void main(String[] args) {
        String str = "aaa(*)";
        System.out.println(str.substring(0,str.indexOf("(*)")));

    }
    }
